/*
    RExLib project, file rvector.cpp
    Copyright (C) 2012  Sarvaritdinov Ravil ra9oaj@gmail.com

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef _RVECTOR_CPP_
#define _RVECTOR_CPP_

#include "rvector.h"

namespace rex {

template <typename T> RVector<T>::RVector()
{
  _cnt = 0;
  _free = 2;
  _tmp = 0;
  sz = sizeof ( T );
  _array = ( T* ) malloc ( 2*sz );

}

template <typename T> RVector<T>::RVector ( const RVector<T>& other )
{

}

template <typename T> RVector<T>::~RVector()
{
  if ( _array )
    {
      for ( int i = 0; i < _cnt; ++i )
        _array[i].~T();

      free ( _array );
    }
  delete _tmp;
}

template <typename T> RVector<T>& RVector<T>::operator= ( const RVector<T>& other )
{
  return *this;
}

template <typename T> bool RVector<T>::operator== ( const RVector<T>& other ) const
{
///TODO: return ...;
}

template <typename T> int RVector<T>::size() const
{
  return _cnt;
}

template <typename T> inline void RVector<T>::insert ( const T &val )
{
  if ( !_free )
    {
      _free = _cnt;
      _array = ( T* ) realloc ( _array, ( _cnt + _free ) * sz );
    }

  new ( &_array[_cnt] ) T ( val );
  --_free;
  ++_cnt;
}

template <typename T> inline bool RVector<T>::insert ( const T &val, int pos )
{
  if ( pos < 0 || ( pos >= _cnt && _cnt ) )
    return false;

  if ( !_cnt && !_free )
    {
      _free = _cnt;
      _array = ( T* ) malloc ( sz * _free );
    }
  else if ( !_free )
    {
      _free = _cnt;
      _array = ( T* ) realloc ( _array, ( _cnt + _free ) * sz );
    }

  memmove ( &_array[pos+1],&_array[pos], ( size_t ) &_array[_cnt] - ( size_t ) &_array[pos] );
  new ( &_array[pos] ) T ( val );
  --_free;
  ++_cnt;
  return true;
}

template <typename T> inline T RVector<T>::value ( int id ) const
{
  if ( id < 0 || id >= _cnt )
    return T();

  return _array[id];
}

template <typename T> inline T RVector<T>::value ( int id, const T &defaultValue ) const
{
  if ( id < 0 || id >= _cnt )
    return defaultValue;

  return _array[id];
}

template <typename T> inline T& RVector<T>::operator[] ( int i )
{
  if ( i < 0 || i >= _cnt )
    {
      delete _tmp;
      _tmp = new T();

      return *_tmp;
    }

  return _array[i];
}

template <typename T> inline T RVector<T>::operator[] ( int i ) const
{
  if ( i < 0 || i >= _cnt )
    return T();

  return _array[i];
}

template <typename T> inline RVector< T >& RVector<T>::operator<< ( const T& val )
{
  insert ( val );
  return *this;
}

template <typename T> typename RVector<T>::iterator RVector<T>::begin() const
{
  if ( !_cnt )
    return 0;

  return _array;
}

template <typename T> typename RVector<T>::iterator RVector<T>::end() const
{
  if ( !_cnt )
    return 0;

  return &_array[_cnt];
}

template <typename T> typename RVector<T>::iterator RVector<T>::at ( int pos ) const
{
  if ( pos < 0 || pos >= _cnt )
    return 0;

  return &_array[pos];
}

template <typename T> inline void RVector<T>::remove ( int id )
{
  if ( id < 0 || id >= _cnt )
    return;

  _array[id].~T();
  memmove ( &_array[id], &_array[id + 1], ( size_t ) &_array[_cnt] - ( size_t ) &_array[id + 1] );
  --_cnt;

  if ( !_cnt )
    {
      free ( _array );
      _array = 0;
      _free = 0;
      return;
    }

  if ( _free == _cnt )
    _array = ( T* ) realloc ( _array, 2*_cnt * sz );
  else
    ++_free;
}

template <typename T> inline void RVector<T>::remove ( int first, int last )
{
  if ( first < 0 || last >= _cnt || first > last )
    return;

  int rm_cnt = last - first + 1;
  for ( int i = first; i <= last; ++i )
    ( _array+i )->~T();

  if ( first == 0 && last + 1 == _cnt )
    {
      free ( _array );
      _free = 0;
      _array = 0;
    }
  else if ( last + 1 == _cnt )
    {
      _array = ( T* ) realloc ( _array, ( _cnt - rm_cnt + _free ) *sz );
    }
  else
    {
      memmove ( &_array[first], &_array[last + 1], ( size_t ) &_array[_cnt] - ( size_t ) &_array[last - 1] );
      if ( _free + rm_cnt > _cnt - rm_cnt )
        {
          _array = ( T* ) realloc ( _array, 2 * _cnt * sz );
          _free = _cnt;
        }
    }

  _cnt -= rm_cnt;
}

template <typename T> void RVector<T>::clear()
{
  if ( _array )
    {
      for ( int i = 0; i < _cnt; ++i )
        _array[i].~T();

      free ( _array );
      _array = 0;
      _cnt = 0;
      _free = 0;
    }
  delete _tmp;
}

}
#endif // _RVECTOR_CPP_
